/*-//GEN-BEGIN:copyright
 * ForBILE - Framework for Building Interactive Learning Environments
 * Computing Institute - Federal University of Alagoas - Brazil
 * Group of Otimization of the Web
 *
 * Copyright (C) 2007 Ig Bittencourt (ig.ibert@gmail.com)
 *		      Camila Nunes (camilapbnunes@hotmail.com)
 *	              Marcos Tadeu (zero.ufal@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *///GEN-END:copyright
package br.ufal.ic.forbile.agents.mediator;

import br.ufal.ic.forbile.agents.ata.cognitive.CognitiveAgentTest;
import br.ufal.ic.forbile.exceptions.ForBILEException;
import br.ufal.ic.forbile.exceptions.PersistenceServiceException;
import br.ufal.ic.forbile.infra.interaction.ontology.Hability;
import java.rmi.RemoteException;
import java.util.logging.Logger;
import br.ufal.ic.forbile.agents.ForBILEAgent;
import br.ufal.ic.forbile.agents.behaviours.GeneralActuator;
import br.ufal.ic.forbile.agents.mediator.behaviours.ManageCognitiveAgents;
import br.ufal.ic.forbile.agents.mediator.behaviours.ATARecommend;
import br.ufal.ic.forbile.agents.mediator.behaviours.RequestPersistence;
import br.ufal.ic.forbile.agents.mediator.behaviours.SensorMediator;
import br.ufal.ic.forbile.agents.mediator.behaviours.SolveProblem;
import br.ufal.ic.forbile.infra.emathema.ontology.Curriculum;
import br.ufal.ic.forbile.log.PersistenceOWLLog;
import br.ufal.ic.utils.Constants;
import br.ufal.ic.utils.RegionServer;
import br.ufal.ic.utils.SharedMem;
import edu.stanford.smi.protegex.owl.model.OWLIndividual;
import edu.stanford.smi.protegex.owl.model.RDFResource;
import jade.core.AID;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import java.io.IOException;
import java.rmi.Naming;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * MediatorAgent1.java
 *
 * <p>A full description of this class.
 *
 * @see SomeRelatedClass.
 *
 * @author <a href="mailto:ig.ibert@gmail.com">ig</a>.
 * @since 0.1
 * @version 0.1
 *
 */
public class MediatorAgent extends ForBILEAgent {
    
    // Constants -----------------------------------------------------
    
    // Attributes ----------------------------------------------------
    private List<Curriculum> curriculums;
    private List<Curriculum> curriculumsAUX;
    
    
    // Static --------------------------------------------------------
    
    private static Logger logger;
    
    static {
        logger = Logger.getLogger(MediatorAgent.class.getName());
    }
    
    // Constructors --------------------------------------------------
    
    /**
     * Creates a new instance of MediatorAgent.
     *
     * @param containerName the jade container name.
     * @param agentLocalName the agent local name.
     */
    public MediatorAgent(final String containerName, final String agentLocalName) {
        super(containerName, agentLocalName);
        this.curriculums = new ArrayList<Curriculum>();
        this.curriculumsAUX = new ArrayList<Curriculum>();
    }
    
    // Public --------------------------------------------------------
    
    /**
     * Responsible for teaching behaviour.
     *
     * @param instrutionalPlan The instrutional plan will be recommeded.
     */
    public void teach(final String instrutionalPlan) {
        addBehaviour(new ATARecommend(instrutionalPlan));
    }
    
    /**
     * Add the behaviour of the cognitive agents.
     *
     * @param agent The ForBILEAgent agent.
     */
    public void manageCognitiveAgents(final ForBILEAgent agent) {
        addBehaviour(new ManageCognitiveAgents(agent));
    }
    
    
    /**
     * Add a behaviour to solve the problem.
     */
    public void solveProblem(){
        addBehaviour(new SolveProblem());
    }
    
    /**
     * Request the agent persistence according to the service and the hability.      
     */
    public void requestATAAgents() {
        boolean hasServices = false;
        AID aid = null;
        
        while (!(hasServices)) {
            try {
                aid = this.searchAgent("RETRIEVE", "EMATHEMA")[0];
                hasServices = true;
            } catch (Exception e) {
                new PersistenceServiceException("Waiting for PersistenceEMATHEMAAgent Services", e);                
            }
            
        }
        
        PersistenceOWLLog persistenceOWLLog = new PersistenceOWLLog();
        persistenceOWLLog.setSubject(null);
        persistenceOWLLog.setPredicate("rdf:type");
        persistenceOWLLog.setObject(":Curriculum");
        persistenceOWLLog.setMethod("RETRIEVE");
        persistenceOWLLog.setRetrieveKey("Map");
        persistenceOWLLog.setOwlFile("emathema");
        try {
            SharedMem mem = (SharedMem) Naming.lookup(RegionServer.HOST_URL);
            mem.getRegion(Constants.OWLPersistence).write(persistenceOWLLog);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        addBehaviour(new RequestPersistence("RETRIEVE", aid));
    }
    
    public void configureSATA() {
        logger.info("SATA configuration started!");
        
        ArrayList<ForBILEAgent> agents = new ArrayList<ForBILEAgent>();
        
        for ( Curriculum o : this.curriculumsAUX ) {
            agents.add(new CognitiveAgentTest("ForBILE-SATA-", ( o.getName() ) ));
        }
        
        logger.info("Adding new agent: " + agents);
        
        ACLMessage message = new ACLMessage(ACLMessage.INFORM);
        
        try {
            message.setProtocol("ADDAGENTSOCIETY");
            message.setContentObject(agents);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        addBehaviour(new GeneralActuator(super.getControllerAgent(), message));
    }
    
    public void configureSATAProtocols(){
        logger.info("SATA configuration protocols started!");
        PersistenceOWLLog persistenceOWLLog = new PersistenceOWLLog();
        try {
            SharedMem mem = (SharedMem) Naming.lookup(RegionServer.HOST_URL);
            persistenceOWLLog = (PersistenceOWLLog) mem.getRegion(Constants.OWLPersistence).retrieveIfExist(persistenceOWLLog);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        for ( Object o : persistenceOWLLog.getRetrieve().keySet() ) {
            
            OWLIndividual owli = (OWLIndividual) persistenceOWLLog.getRetrieve().get(o);
            Curriculum cur = null;
            
            RDFResource res = owli.as(Curriculum.class);
            cur = (Curriculum) res;
            
            this.curriculums.add(cur);
            
        }
        
        configureATAprotocol();
    }
    
    public void configureATAprotocol() {
        if (this.curriculums.isEmpty()) {
            configureSATA();
        } else {
            for ( Curriculum cur : this.curriculums ) {
                this.setATAProtocol(cur);
                break;
            }
        }
    }

    public void ATAAgentConfigured(final String individual, final boolean agentConfigured) {
        logger.info("ATA Agent Configured!");
        if (agentConfigured) {
            for (Curriculum c : this.curriculums) {
                if (c.getName().equalsIgnoreCase(individual)) {
                    this.curriculums.remove(c);
                    this.curriculumsAUX.add(c);
                    logger.info("Agent " + individual + " configured!");
                    configureATAprotocol();
                    break;
                }
            }
            
        } else {
            logger.info("Agent " + individual + " not configured!")  ;
        }
    }

    
    /**
     * Search the agent according to the service and the hability.
     *
     * @param service The agent's service.
     * @param hability The agent's hability.
     *
     * @return All the agents' AID found.
     */
    public AID[] searchAgent(final String service, final String hability) {
        
        ServiceDescription serviceDescription = new ServiceDescription();
        serviceDescription.setName( service );
        serviceDescription.setType( hability );
        
        DFAgentDescription agentDescription = new DFAgentDescription();
        agentDescription.addServices(serviceDescription);
        try{
            DFAgentDescription results[] = DFService.search(this,agentDescription);
            AID[] aid = new AID[results.length];
            for (int i = 0; i < results.length; i++) {
                aid[i] = results[i].getName();
            }
            return aid;
        } catch (FIPAException e){
            logger.info("Returns null");
            return null;
        }
    }
    
// ForBILEAgent implementation ------------------------------------
    
    protected void sensor() {
        addBehaviour(new SensorMediator(this, SENSOR_TIME));
    }
    
// Y overrides ---------------------------------------------------
    
// Package protected ---------------------------------------------
    
// Protected -----------------------------------------------------
    
// Private -------------------------------------------------------
    
    private void setATAProtocol(final Curriculum curriculum) {
        Map<String, Object> configuration = new HashMap<String, Object>();
        
        configuration.put("Name", Hability.class);
        
        configuration.put("Individual", curriculum.getName());
        configuration.put("habilityName", curriculum.getName());
        //configuration.put("isChild", "Teach");

        boolean hasServices = false;
        AID aid = null;
        
        while (!(hasServices)) {
            try {
                aid = this.searchAgent("CREATE", "INTERACTION")[0];
                logger.info("Agent found: " + aid);
                hasServices = true;
            } catch (Exception e) {
                new PersistenceServiceException("Waiting for PersistenceOWLAgentInteraction Services", e);
            }
        }
        
        PersistenceOWLLog persistenceOWLLog = new PersistenceOWLLog();
        
        persistenceOWLLog.setMethod("CREATE");
        persistenceOWLLog.setOwlFile("interaction");
        persistenceOWLLog.setConfiguration(configuration);
        try {
            SharedMem mem = (SharedMem) Naming.lookup(RegionServer.HOST_URL);
            mem.getRegion(Constants.OWLPersistence).write(persistenceOWLLog);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        logger.info("Critical Region used");
        addBehaviour(new RequestPersistence("CREATE", aid));
    }
    
// Inner classes -------------------------------------------------
    
}
